package framework.mvc;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Calendar;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.apache.commons.lang.StringUtils;
import org.jdesktop.swingx.JXDatePicker;

import framework.component.combobox.TComboBox;
import framework.component.field.TTextField;
import framework.util.TDateUtils;
import framework.util.TReflectionUtils;

public abstract class GenericView<ENTIDADE extends Object> extends JDialog {

	private static final long serialVersionUID = -6866826489234846630L;

	protected GenericController<ENTIDADE> controller;

	private boolean eventosCriados = false;

	public GenericView(GenericController<ENTIDADE> controller) {
		this.controller = controller;
		controller.setView(this);
		this.setModal(true);
	}

	public GenericController<ENTIDADE> getController() {
		return controller;
	}

	public void setController(GenericController<ENTIDADE> controller) {
		this.controller = controller;
	}

	@Override
	public void setVisible(boolean arg0) {
		if (!eventosCriados) {
			registrarEventos(this);
			eventosCriados = true;
		}
		super.setVisible(arg0);
	}

	@Override
	public void setSize(Dimension d) {
		super.setSize(d);
		try {
			setLocationRelativeTo(null);
		} catch (StackOverflowError e) {

		}
	}

	@Override
	public void setSize(int width, int height) {
		super.setSize(width, height);
		try {
			setLocationRelativeTo(null);
		} catch (StackOverflowError e) {

		}
	}

	@Override
	public void setBounds(int x, int y, int width, int height) {
		super.setBounds(x, y, width, height);
		try {
			setLocationRelativeTo(null);
		} catch (StackOverflowError e) {

		}
	}

	@Override
	public void setBounds(Rectangle r) {
		super.setBounds(r);
		try {
			setLocationRelativeTo(null);
		} catch (StackOverflowError e) {

		}
	}

	private void registrarEventos(Container container) {
		for (Component component : container.getComponents()) {
			if (component instanceof Container) {
				registrarEventos((Container) component);
			}
			final String nomeComponente = component.getName();

			if (component instanceof JButton) {
				JButton button = (JButton) component;
				button.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent arg0) {
						TReflectionUtils.chamarMetodo(controller,
								nomeComponente);
					}
				});
			}

			if (component instanceof JRadioButton) {
				JRadioButton button = (JRadioButton) component;
				button.addItemListener(new ItemListener() {
					@Override
					public void itemStateChanged(ItemEvent e) {
						TReflectionUtils.chamarMetodo(controller,
								nomeComponente);
					}
				});
			}

		}
	}

	public void atualizarView() {
		atualizarView(this);
	}

	private void atualizarView(Container container) {
		for (Component component : container.getComponents()) {
			if (component instanceof Container) {
				atualizarView((Container) component);
			}
			String nome = component.getName();
			String metodo = "get" + StringUtils.capitalize(nome);
			Object valor = TReflectionUtils.chamarMetodo(controller.getModel()
					.getEntidade(), metodo);
			if (valor != null) {
				if (component instanceof JTextField) {
					JTextField field = (JTextField) component;
					field.setText(valor.toString());
				} else if (component instanceof JTextArea) {
					JTextArea field = (JTextArea) component;
					field.setText((String) valor);
				} else if (component instanceof JCheckBox) {
					JCheckBox check = (JCheckBox) component;
					check.setSelected(false);
					check.setSelected((Boolean) valor);
				} else if (component instanceof JXDatePicker) {
					JXDatePicker datePicker = (JXDatePicker) component;
					datePicker.setDate(TDateUtils.toDate((Calendar) valor));
				} else if (component instanceof TComboBox) {
					TComboBox combo = (TComboBox) component;
					combo.setRegistroSelecionado(valor);
				} else if (component instanceof JComboBox) {
					JComboBox combo = (JComboBox) component;
					combo.getEditor().setItem(valor);
				}
			}
		}
	}

	public void atualizarModel() {
		atualizarModel(this);
	}

	private void atualizarModel(Container container) {
		for (Component component : container.getComponents()) {
			if (component instanceof Container) {
				atualizarModel((Container) component);
			}
			String nome = component.getName();
			String metodo = "set" + StringUtils.capitalize(nome);

			if (component instanceof TTextField) {
				TTextField field = (TTextField) component;
				switch (field.getTipoDado()) {
				case TTextField.INTEGER:
					TReflectionUtils.chamarMetodoParametros(controller
							.getModel().getEntidade(), metodo, Integer
							.parseInt(field.getText()));
					break;
				case TTextField.DOUBLE:
				case TTextField.DOUBLE_NEGATIVO:
					TReflectionUtils.chamarMetodoParametros(controller
							.getModel().getEntidade(), metodo, Double
							.parseDouble(field.getText()));
					break;
				case TTextField.FLOAT:
					TReflectionUtils.chamarMetodoParametros(controller
							.getModel().getEntidade(), metodo, Double
							.parseDouble(field.getText()));
					break;
				default:
					TReflectionUtils.chamarMetodoParametros(controller
							.getModel().getEntidade(), metodo, field.getText());
				}
			}

			else if (component instanceof JTextField) {
				JTextField field = (JTextField) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, field.getText());
			} else if (component instanceof JTextArea) {
				JTextArea field = (JTextArea) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, field.getText());
			} else if (component instanceof JCheckBox) {
				JCheckBox check = (JCheckBox) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, check.isSelected());
			} else if (component instanceof JXDatePicker) {
				JXDatePicker datePicker = (JXDatePicker) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, TDateUtils
						.toCalendar(datePicker.getDate()));
			} else if (component instanceof TComboBox) {
				TComboBox combo = (TComboBox) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, combo.getRegistroSelecionado());
			} else if (component instanceof JComboBox) {
				JComboBox combo = (JComboBox) component;
				TReflectionUtils.chamarMetodoParametros(controller.getModel()
						.getEntidade(), metodo, combo.getSelectedItem());
			}
		}
	}

	public GenericModel<ENTIDADE> getModel() {
		return controller.getModel();
	}

	public GenericDAO<ENTIDADE> getDAO() {
		return controller.getDao();
	}

	public void abrir() {
		setVisible(true);
	}

}